package validate

import (
	"github.com/ghodss/yaml"
	"github.com/pkg/errors"
	"gitverse.ru/synapse/kubelatte/pkg/api/v1alpha1"
	"gitverse.ru/synapse/kubelatte/pkg/logs"
	"os"
)

const (
	Mutation   = "mutation"
	Validation = "validation"
)

type Rules struct {
	MutationRuleConfig   []v1alpha1.Item
	ValidationRuleConfig []v1alpha1.Item
}

type RuleSpec struct {
	Type  string          `yaml:"type"`
	Items []v1alpha1.Item `yaml:"items,flow"`
}

type Rule struct {
	Simples []Simple `yaml:"simples"`
	Rego    Rego     `yaml:"rego"`
}

type Rego struct {
	Template   string `yaml:"template"`
	Parameters string `yaml:"parameters"`
}

type Simple struct {
	Name    string `yaml:"name"`
	Path    string `yaml:"path"`
	Value   string `yaml:"value"`
	Action  string `yaml:"action"`
	Message string `yaml:"message"`
}

type Match struct {
	Kinds               []Kinds           `yaml:"kinds"`
	NamespaceSelector   NamespaceSelector `yaml:"namespaceSelector"`
	LabelSelector       LabelSelector     `yaml:"labelSelector"`
	UserInfo            UserInfo          `yaml:"userInfo"`
	Name                string            `yaml:"name"`
	Scope               string            `yaml:"scope"`
	ExcludedNamespaces  []string          `yaml:"excludedNamespaces"`
	Namespaces          []string          `yaml:"namespaces"`
	Operations          []string          `yaml:"operations"`
	AnnotationNamespace string            `yaml:"annotationNamespace"`
	AnnotationTrigger   string            `yaml:"annotationTrigger"`
}

type UserInfo struct {
	Username string `yaml:"username"`
}

type Kinds struct {
	Kinds     []string `yaml:"kinds"`
	ApiGroups []string `yaml:"apiGroups"`
}

type NamespaceSelector struct {
	MatchExpressions []MatchExpression `yaml:"matchExpressions"`
}

type LabelSelector struct {
	MatchExpressions []MatchExpression `yaml:"matchExpressions"`
}

type MatchExpression struct {
	Key      string   `yaml:"key"`
	Operator string   `yaml:"operator"`
	Values   []string `yaml:"values"`
}

const (
	Deny    = "deny"
	Allow   = "allow"
	Enabled = "enabled"
)

type lsOperator string

const (
	In           lsOperator = "In"
	NotIn        lsOperator = "NotIn"
	Exists       lsOperator = "Exists"
	DoesNotExist lsOperator = "DoesNotExist"
)

// parse parses mutation configs
func parse(configFilePath string) (rule *RuleSpec, err error) {
	configFile, err := os.ReadFile(configFilePath)
	if err != nil {
		return nil, err
	}
	logs.Debugf("Read scope config with name %s body\n%s", configFile, string(configFile))
	r := &RuleSpec{}
	err = yaml.Unmarshal(configFile, r)
	if err != nil {
		return nil, err
	}

	return r, nil
}

func NewRuleConfigs(ruleConfigsFile string) (*RuleSpec, error) {
	config, err := parse(ruleConfigsFile)
	if err != nil {
		return nil, errors.Errorf("api=NewRuleConfigs, reason=parse, ruleConfigsFile=%q, err=%v", ruleConfigsFile, err)
	}
	return config, nil
}

func MergeRuleConfigs(filePath string, rulecfg *Rules) error {
	configs, err := NewRuleConfigs(filePath)
	if err != nil {
		return err
	}
	if configs.Type == Mutation {
		rulecfg.MutationRuleConfig = append(rulecfg.MutationRuleConfig, configs.Items...)
	} else if configs.Type == Validation {
		rulecfg.ValidationRuleConfig = append(rulecfg.ValidationRuleConfig, configs.Items...)
	}

	return nil
}

type Validator struct {
	Rules []v1alpha1.Item
}

func (v *Validator) SetRules(rules []v1alpha1.Item) *Validator {
	if len(v.Rules) == 0 {
		r := make([]v1alpha1.Item, len(rules))
		v.Rules = r
	}
	copy(v.Rules, rules)
	return v
}
